
<!DOCTYPE HTML>
<html lang="zh-hans" >
    <head>
        <meta charset="UTF-8">
        <title>1 基础知识 · C++导览 第二版 简体中文版</title>
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta name="description" content="">
        <meta name="generator" content="HonKit 5.1.1">
        <meta name="author" content="Windsting">
        
        
    
    <link rel="stylesheet" href="gitbook/style.css">

    
            
                
                <link rel="stylesheet" href="gitbook/@dogatana/honkit-plugin-page-toc-button/plugin.css">
                
            
                
                <link rel="stylesheet" href="gitbook/@dogatana/honkit-plugin-back-to-top-button/plugin.css">
                
            
                
                <link rel="stylesheet" href="gitbook/gitbook-plugin-forkmegithub/plugin.css">
                
            
                
                <link rel="stylesheet" href="gitbook/@honkit/honkit-plugin-highlight/website.css">
                
            
                
                <link rel="stylesheet" href="gitbook/gitbook-plugin-search/search.css">
                
            
                
                <link rel="stylesheet" href="gitbook/gitbook-plugin-fontsettings/website.css">
                
            
        

    

    
        
        <link rel="stylesheet" href="styles/website.css">
        
    
        
    
        
    
        
    
        
    
        
    

        
    
    
    <meta name="HandheldFriendly" content="true"/>
    <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="apple-mobile-web-app-status-bar-style" content="black">
    <link rel="apple-touch-icon-precomposed" sizes="152x152" href="gitbook/images/apple-touch-icon-precomposed-152.png">
    <link rel="shortcut icon" href="gitbook/images/favicon.ico" type="image/x-icon">

    
    <link rel="next" href="ch02.html" />
    
    
    <link rel="prev" href="./" />
    

    </head>
    <body>
        
<div class="book honkit-cloak">
    <div class="book-summary">
        
            
<div id="book-search-input" role="search">
    <input type="text" placeholder="输入并搜索" />
</div>

            
                <nav role="navigation">
                


<ul class="summary">
    
    
    
        
        <li>
            <a href="https://github.com/windsting/a-tour-of-cpp-2nd-cn" target="_blank" class="custom-link">Github Link</a>
        </li>
    
    

    
    <li class="divider"></li>
    

    
        
        
    
        <li class="chapter " data-level="1.1" data-path="translation_note.html">
            
                <a href="translation_note.html">
            
                    
                    译者言
            
                </a>
            

            
        </li>
    
        <li class="chapter " data-level="1.2" data-path="./">
            
                <a href="./">
            
                    
                    前言
            
                </a>
            

            
        </li>
    
        <li class="chapter active" data-level="1.3" data-path="ch01.html">
            
                <a href="ch01.html">
            
                    
                    1 基础知识
            
                </a>
            

            
        </li>
    
        <li class="chapter " data-level="1.4" data-path="ch02.html">
            
                <a href="ch02.html">
            
                    
                    2 用户定义类型
            
                </a>
            

            
        </li>
    
        <li class="chapter " data-level="1.5" data-path="ch03.html">
            
                <a href="ch03.html">
            
                    
                    3 模块化
            
                </a>
            

            
        </li>
    
        <li class="chapter " data-level="1.6" data-path="ch04.html">
            
                <a href="ch04.html">
            
                    
                    4 类
            
                </a>
            

            
        </li>
    
        <li class="chapter " data-level="1.7" data-path="ch05.html">
            
                <a href="ch05.html">
            
                    
                    5 基本操作
            
                </a>
            

            
        </li>
    
        <li class="chapter " data-level="1.8" data-path="ch06.html">
            
                <a href="ch06.html">
            
                    
                    6 模板
            
                </a>
            

            
        </li>
    
        <li class="chapter " data-level="1.9" data-path="ch07.html">
            
                <a href="ch07.html">
            
                    
                    7 概束和泛型编程
            
                </a>
            

            
        </li>
    
        <li class="chapter " data-level="1.10" data-path="ch08.html">
            
                <a href="ch08.html">
            
                    
                    8 标准库概览
            
                </a>
            

            
        </li>
    
        <li class="chapter " data-level="1.11" data-path="ch09.html">
            
                <a href="ch09.html">
            
                    
                    9 字符串和正则表达式
            
                </a>
            

            
        </li>
    
        <li class="chapter " data-level="1.12" data-path="ch10.html">
            
                <a href="ch10.html">
            
                    
                    10 输入输出
            
                </a>
            

            
        </li>
    
        <li class="chapter " data-level="1.13" data-path="ch11.html">
            
                <a href="ch11.html">
            
                    
                    11 容器
            
                </a>
            

            
        </li>
    
        <li class="chapter " data-level="1.14" data-path="ch12.html">
            
                <a href="ch12.html">
            
                    
                    12 算法
            
                </a>
            

            
        </li>
    
        <li class="chapter " data-level="1.15" data-path="ch13.html">
            
                <a href="ch13.html">
            
                    
                    13 实用功能
            
                </a>
            

            
        </li>
    
        <li class="chapter " data-level="1.16" data-path="ch14.html">
            
                <a href="ch14.html">
            
                    
                    14 数值
            
                </a>
            

            
        </li>
    
        <li class="chapter " data-level="1.17" data-path="ch15.html">
            
                <a href="ch15.html">
            
                    
                    15 并发
            
                </a>
            

            
        </li>
    
        <li class="chapter " data-level="1.18" data-path="ch16.html">
            
                <a href="ch16.html">
            
                    
                    16 历史及兼容性
            
                </a>
            

            
        </li>
    
        <li class="chapter " data-level="1.19" data-path="idx.html">
            
                <a href="idx.html">
            
                    
                    索引
            
                </a>
            

            
        </li>
    

    

    <li class="divider"></li>

    <li>
        <a href="https://github.com/honkit/honkit" target="blank" class="gitbook-link">
            本书使用 HonKit 发布
        </a>
    </li>
</ul>


                </nav>
            
        
    </div>

    <div class="book-body">
        
            <div class="body-inner">
                
                    

<div class="book-header" role="navigation">
    

    <!-- Title -->
    <h1>
        <i class="fa fa-circle-o-notch fa-spin"></i>
        <a href="." >1 基础知识</a>
    </h1>
</div>




                    <div class="page-wrapper" tabindex="-1" role="main">
                        <div class="page-inner">
                            
<div id="book-search-results">
    <div class="search-noresults">
    
                                <section class="normal markdown-section">
                                

    
        
                                <p><a class="en-page-number" id="1"></a></p>
<div class="chapter-number"><p class="chapter-number">1</p></div>

<h1 id="the-basics">基础知识 </h1>
<blockquote>
<p>我们要做的第一件事儿，</p>
<p>就是把律师统统杀光。</p>
<p>—— <span title="外语教学与研究出版社 2015年10月 出版的《亨利六世 中：英汉对照》 由 覃学岚 译。 —— 译者注">《亨利六世》（中）</span><sup><a href="#fn_1" id="reffn_1">1</a></sup></p>
</blockquote>
<h2 id="1.1">1.1 导言 </h2>
<p>本章将简略地呈现C++的文法、内存模型和计算模型，和把代码组织成程序的基本机制。
这部分语言特性所支持的编程风格常见于 C，
也被称为<em>过程式编程（procedural programming）</em>。</p>
<p><a class="en-page-number" id="2"></a></p>
<h2 id="1.2">1.2 程序 </h2>
<p>C++是种编译型语言。要运行一个程序，其源文本需要通过编译器处理，
生成一些目标文件，再经链接器组合后给出一个可执行文件。
一个典型的C++程序要使用多个源代码文件（通常简称为<em>源文件(source files)</em>）生成。</p>
<p><img src="img/ch01_01.png" alt="compiling process"></p>
<p>可执行文件针对特定的 硬件/操作系统 组合而生成，不可移植，比方说，
不能从 Mac系统 拿到 Windows系统 上运行。
当我们说到 C++ 程序的可移植性时，一般是在说源代码的可移植性；
就是说，这份源码可以在多个系统上被编译并运行。</p>
<p>ISO C++ 标准定义了两类东西：</p>
<ul>
<li>语言核心特性(core language features)，
  诸如内置的类型（例如 <code>char</code> 和 <code>int</code>）
  以及循环（例如 <code>for</code>-语句 和 <code>while</code>-语句）</li>
<li>标准库组件(standard-library components)，
  诸如容器（例如 <code>vector</code> 和 <code>map</code>）
  以及 I/O 操作（例如 <code>&lt;&lt;</code> 和 <code>getline()</code>）</li>
</ul>
<p>标准库组件完全是普通的 C++ 代码，由具体的 C++ 实现提供。
换句话说， C++ 标准库可以且确实是用 C++ 自身
(包括少量的机器语言代码，用于线程上下文切换等功能)实现的。
这意味着，对多数需求严苛的系统编程而言，C++ 具有足够的表达能力和效率。</p>
<p>C++ 是静态类型语言。
就是说，任何一个东西（例如对象、值、名称和表达式）被用到的时候，
编译器都必须已经知晓其类型。对象的类型确定了可施加操作的集合。</p>
<h3 id="1.2.1">1.2.1 Hello, World! </h3>
<p>最小的 C++ 程序是</p>
<pre><code class="lang-cpp"><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span>{}    <span class="hljs-comment">// 最小的 C++ 程序</span>
</code></pre>
<p>这定义了一个名为<code>main</code>的函数，它不接受参数，也不执行任何操作。</p>
<p>花括号<code>{}</code>，在 C++ 中表示结组。在此处，它标示了函数体的起止点。
双斜杠，<code>//</code>，发起一个注释并延续至行尾。
注释是供人阅读的，编译器忽略所有注释。</p>
<p>每个 C++ 程序必须有且只有一个名为<code>main()</code>的全局函数。
整个程序由该函数开始执行。
如果<code>main()</code>返回了任何<code>int</code>整数值，该值被返回给“系统”。
如果没有返回值，系统会接收到一个值，表示执行成功。
<code>main()</code>返回的非零值表示出错。并非所有操作系统和执行环境都会用到这个返回值。
基于 Linux/Unix 的环境用它，而基于 Windows 的环境几乎不用。</p>
<p><a class="en-page-number" id="3"></a></p>
<p>一般来说，程序会有些输出，以下程序写出<code>Hello, World!</code>：</p>
<pre><code class="lang-cpp"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string">&lt;iostream&gt;</span></span>

<span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span>
</span>{
    std::cout &lt;&lt; <span class="hljs-string">&quot;Hello, World!\n&quot;</span>;
}
</code></pre>
<p><code>#include &lt;iostream&gt;</code>这行告诉编译器，
在<code>iostream</code>中查找标准输入输出流相关的声明，并把它们<em>包含（include）</em>进来。
如果缺少了这些声明，以下表达式</p>
<pre><code class="lang-cpp">std::cout &lt;&lt; <span class="hljs-string">&quot;Hello, World!\n&quot;</span>
</code></pre>
<p>就无效了。操作符<code>&lt;&lt;</code>(“输向”)把它的第二个参数写入第一个。
在本例中，字符串文本(string literal)<code>&quot;Hello, World!\n&quot;</code>
被写入到标准输出流<code>std::cout</code>上。
字符串文本是由双引号包围的一连串字符。
在字符串文本中，反斜杠<code>\</code>后跟一字符共同表示一个“特殊字符”。
在这里，<code>\n</code>是换行符，所以写出的字符是<code>Hello, World!</code>紧跟一个换行。</p>
<p><code>std::</code>指出名称<code>cout</code>需要在标准库（standard-library）命名空间（§3.4）中查找。
我在谈论标准功能的时候通常略掉<code>std::</code>；
§3.4 里展示了一个方法，无需显式指出命名空间名，就可以让其中的名称可见。</p>
<p>一般来说，所有的可执行代码都会被置于函数中，
再由<code>main()</code>函数直接或者间接地调用，例如：</p>
<pre><code class="lang-cpp"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string">&lt;iostream&gt;</span>         <span class="hljs-comment">// 包含（“引入”）I/O 流程序库的声明</span></span>

<span class="hljs-keyword">using</span> <span class="hljs-keyword">namespace</span> std;        <span class="hljs-comment">// 让std里的名称无需使用 std:: 就可见 (§3.4)</span>

<span class="hljs-function"><span class="hljs-type">double</span> <span class="hljs-title">square</span><span class="hljs-params">(<span class="hljs-type">double</span> x)</span>     <span class="hljs-comment">// 计算一个双精度浮点数的平方</span>
</span>{
    <span class="hljs-keyword">return</span> x*x;
}

<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">print_square</span><span class="hljs-params">(<span class="hljs-type">double</span> x)</span>
</span>{
    cout &lt;&lt; <span class="hljs-string">&quot;the square of &quot;</span> &lt;&lt; x &lt;&lt; <span class="hljs-string">&quot; is &quot;</span> &lt;&lt; <span class="hljs-built_in">square</span>(x) &lt;&lt; <span class="hljs-string">&quot;\n&quot;</span>;
}

<span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span>
</span>{
    <span class="hljs-built_in">print_square</span>(<span class="hljs-number">1.234</span>);    <span class="hljs-comment">// 打印：the square of 1.234 is 1.52276</span>
}
</code></pre>
<p>如果“返回类型”为<code>void</code>，表示该函数不返回任何值。</p>
<p><a class="en-page-number" id="4"></a></p>
<h2 id="1.3">1.3 函数 </h2>
<p>如果在 C++ 程序里要做一件事，主要的方式是调用某个函数去执行它。
定义函数就是指定某个操作怎样被执行。
除非事先声明过，否则函数无法被调用。</p>
<p>函数声明给出了该函数的名称、返回值类型（如果有的话）、
以及调用它时必须提供的参数数量和类型。例如：</p>
<pre><code class="lang-cpp"><span class="hljs-function">Elem* <span class="hljs-title">next_elem</span><span class="hljs-params">()</span></span>;      <span class="hljs-comment">// 不接受参数；返回指向 Elem 的指针（一个 Elem*）</span>
<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">exit</span><span class="hljs-params">(<span class="hljs-type">int</span>)</span></span>;         <span class="hljs-comment">// int 参数；无返回值</span>
<span class="hljs-function"><span class="hljs-type">double</span> <span class="hljs-title">sqrt</span><span class="hljs-params">(<span class="hljs-type">double</span>)</span></span>;    <span class="hljs-comment">// double 参数；返回一个 double</span>
</code></pre>
<p>在函数声明中，返回值出现在名称前面，参数类型被括在小括号里，跟在名称后面。</p>
<p>参数传递的语法跟初始化（§3.6.1）的语法一致。
就是说，会检查参数类型，在必要的时候会对参数进行隐式类型转换（§1.4）。例如：</p>
<pre><code class="lang-cpp"><span class="hljs-type">double</span> s2 = <span class="hljs-built_in">sqrt</span>(<span class="hljs-number">2</span>);        <span class="hljs-comment">// 以 double 类型参数 double{2} 调用 sqrt()</span>
<span class="hljs-type">double</span> s3 = <span class="hljs-built_in">sqrt</span>(<span class="hljs-string">&quot;three&quot;</span>);  <span class="hljs-comment">// 错误：sqrt() 要求参数类型为 double</span>
</code></pre>
<p>编译期类型检查和类型转换的价值至关重要。</p>
<p>函数声明中可以包含参数名。
这对程序的读者有益，但除非该声明同时也是函数定义，编译器将忽略这些参数名。例如：</p>
<pre><code class="lang-cpp"><span class="hljs-function"><span class="hljs-type">double</span> <span class="hljs-title">sqrt</span><span class="hljs-params">(<span class="hljs-type">double</span> d)</span></span>; <span class="hljs-comment">// 返回 d 的平方根</span>
<span class="hljs-function"><span class="hljs-type">double</span> <span class="hljs-title">square</span><span class="hljs-params">(<span class="hljs-type">double</span>)</span></span>; <span class="hljs-comment">// 返回参数的平方</span>
</code></pre>
<p>函数的类型包含返回值类型和参数类型序列。例如：</p>
<pre><code class="lang-cpp"><span class="hljs-function"><span class="hljs-type">double</span> <span class="hljs-title">get</span><span class="hljs-params">(<span class="hljs-type">const</span> vector&lt;<span class="hljs-type">double</span>&gt;&amp; vec, <span class="hljs-type">int</span> index)</span></span>; <span class="hljs-comment">// 类型： double(const vector&lt;double&gt;&amp;,int)</span>
</code></pre>
<p>函数可以作为类（§2.3, §4.2.1）的成员。
对于<em>成员函数（member function）</em>来说，类名也是该函数类型的组成部分。例如：</p>
<pre><code class="lang-cpp"><span class="hljs-type">char</span>&amp; String::<span class="hljs-keyword">operator</span>[](<span class="hljs-type">int</span> index); <span class="hljs-comment">// 类型： char&amp; String::(int)</span>
</code></pre>
<p>我们希望代码可读性好，因为这是可维护性的前提。
而可读性的前提是，将运算任务拆分成有意义的小块（体现为函数和类），并为其命名。
如同类型（内置类型和用户定义类型）为数据提供基本的词汇表那样，函数为运算提供词汇表。
C++ 标准算法（例如 <code>find</code>, <code>sort</code> 和 <code>iota</code>）开了个好头。
然后，我们可以编排函数，把通用或专用的作业表示成更大型的运算任务。</p>
<p>代码的报错数量跟代码的量和复杂度有关。
这两个问题都可以通过更多、更简短的函数来解决。
使用函数完成一项特定任务，总是能搭救我们，避免在其它代码中再敲入一段特定的代码；
创建函数会促使我们给一个行为命名并给它单独创建文档。</p>
<p>如果两个函数以同样的名称定义，但使用不同的参数类型，编译器将选用最恰当的函数调用。
例如：</p>
<p><a class="en-page-number" id="5"></a></p>
<pre><code class="lang-cpp"><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">print</span><span class="hljs-params">(<span class="hljs-type">int</span>)</span></span>;    <span class="hljs-comment">// 接收一个整型参数</span>
<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">print</span><span class="hljs-params">(<span class="hljs-type">double</span>)</span></span>; <span class="hljs-comment">// 接收一个浮点型参数</span>
<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">print</span><span class="hljs-params">(string)</span></span>; <span class="hljs-comment">// 接收一个 string 参数</span>

<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">user</span><span class="hljs-params">()</span>
</span>{
    <span class="hljs-built_in">print</span>(<span class="hljs-number">42</span>);          <span class="hljs-comment">// 调用 print(int)</span>
    <span class="hljs-built_in">print</span>(<span class="hljs-number">9.65</span>);        <span class="hljs-comment">// 调用 print(double)</span>
    <span class="hljs-built_in">print</span>(<span class="hljs-string">&quot;Barcelona&quot;</span>); <span class="hljs-comment">// 调用 print(string)</span>
}
</code></pre>
<p>如果有两个备选函数可供调用，但都不优于另一个，
此次调用将被判定为具有二义性，编译器会报错。例如：</p>
<pre><code class="lang-cpp"><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">print</span><span class="hljs-params">(<span class="hljs-type">int</span>,<span class="hljs-type">double</span>)</span></span>;
<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">print</span><span class="hljs-params">(<span class="hljs-type">double</span>,<span class="hljs-type">int</span>)</span></span>;

<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">user2</span><span class="hljs-params">()</span>
</span>{
    <span class="hljs-built_in">print</span>(<span class="hljs-number">0</span>,<span class="hljs-number">0</span>); <span class="hljs-comment">// 错误：二义性</span>
}
</code></pre>
<p>多个同名函数的定义被称为<em>函数重载（function overloading）</em>，
是泛型编程(§7.2)的重要组成部分。
当函数被重载，所有同名函数应当具有相同的语义。
<code>print()</code>函数就是这样的示例；每个<code>print()</code>函数都打印其参数。</p>
<h2 id="1.4">1.4 类型，变量和算术运算 </h2>
<p>所有的名称、表达式都具有类型，以确定可执行的运算。例如，声明</p>
<pre><code class="lang-cpp"><span class="hljs-type">int</span> inch;
</code></pre>
<p>指出，<code>inch</code>的类型是<code>int</code>；也就是说，<code>inch</code>是个整数变量。</p>
<p><em>声明（declaration）</em> 是把一个实体引入程序的语句。它规定了这个实体的类型：</p>
<ul>
<li><em>类型（type）</em> 规定了一组可能的值和一组（针对对象的）运算</li>
<li><em>对象（object）</em> 是一块内存，其中承载某种类型的值</li>
<li><em>值（value）</em> 是一些二进制位，其含义由某个类型规定</li>
<li><em>变量（variable）</em> 是一个具名对象</li>
</ul>
<p>C++ 提供了一小撮基本类型，既然我并非组织学家，也就不把它们全部逐一列出了。
如果需要完整列表，可以求助参考资料，
例如网络上的 [Stroustrup,2013] 或者 [Cppreference]。
举几个例子：</p>
<p><a class="en-page-number" id="6"></a></p>
<pre><code class="lang-cpp"><span class="hljs-type">bool</span>        <span class="hljs-comment">// 布尔类型，可能的值是 true 和 false</span>
<span class="hljs-type">char</span>        <span class="hljs-comment">// 字符，例如：&apos;a&apos;、&apos;z&apos; 和 &apos;9&apos;</span>
<span class="hljs-type">int</span>         <span class="hljs-comment">// 整数，例如：-273、42、和 1066</span>
<span class="hljs-type">double</span>      <span class="hljs-comment">// 双精度浮点数，例如：-273.15、3.14 和 6.626e-34</span>
<span class="hljs-type">unsigned</span>    <span class="hljs-comment">// 非负整数，例如：0、1、和 999 (用于逻辑位运算)</span>
</code></pre>
<p>每个基本类型都直接对应于硬件结构，其容量是固定的，
该容量决定了其中存储的值的取值范围。</p>
<p><img src="img/ch01_02.png" alt="size of types"></p>
<p><code>char</code>类型变量，在给定的机器上是保存一个字符的自然大小（通常是个8比特位的字节），
其余类型的容量都是<code>char</code>的整数倍。
类型的容量是实现定义的（就是说，在不同的机器上可以不一样），
可使用<code>sizeof</code>运算符获取；例如：
<code>sizeof(char)</code> 等于 <code>1</code>，<code>sizeof(int)</code> 则通常是<code>4</code>。</p>
<p>数字可以是浮点数或者整数。</p>
<ul>
<li>浮点数通过小数点识别（如：<code>3.14</code>）或者使用科学计数法（如：<code>3e-2</code>）。</li>
<li>整数文本默认是十进制（如：<code>42</code>的意思是四十二）。
  前缀<code>0b</code>表示二进制（基数是2）整数文本（如：<code>0b10101010</code>）。
  前缀<code>0x</code>表示十六进制（基数是16）整数文本（如：<code>0xBAD1234</code>）。
  前缀<code>0</code>表示八进制（基数是8）整数文本（如：<code>0334</code>）。</li>
</ul>
<p>为提高长文本的可读性，可以使用单引号（<code>&apos;</code>）作为数字分隔符。
例如：<em>π</em> 大概是 <code>3.14159&apos;26535&apos;89793&apos;23846&apos;26433&apos;83279&apos;50288</code>，
如果用十六进制就是 <code>0x3.243F&apos;6A88&apos;85A3&apos;08D3</code>。</p>
<h3 id="1.4.1">1.4.1 算术运算 </h3>
<p>算术运算符可以对基本类型进行适当的组合：</p>
<pre><code class="lang-cpp">x+y     <span class="hljs-comment">// 加法（plus）</span>
+x      <span class="hljs-comment">// 一元加（unary plus）</span>
x-y     <span class="hljs-comment">// 减法（minus）</span>
-x      <span class="hljs-comment">// 一元减（unary minus）</span>
x*y     <span class="hljs-comment">// 乘法（multiply）</span>
x/y     <span class="hljs-comment">// 除法（divide）</span>
x%y     <span class="hljs-comment">// 对整数取余(取模)（remainder(modulus)）</span>
</code></pre>
<p>比较运算符也是这样：</p>
<p><a class="en-page-number" id="7"></a></p>
<pre><code class="lang-cpp">x==y    <span class="hljs-comment">// 相等（equal）</span>
x!=y    <span class="hljs-comment">// 不等（not equal）</span>
x&lt;y     <span class="hljs-comment">// 小于（less than）</span>
x&gt;y     <span class="hljs-comment">// 大于（greater than）</span>
x&lt;=y    <span class="hljs-comment">// 小于等于（less than or equal）</span>
x&gt;=y    <span class="hljs-comment">// 大于等于（greater than or equal）</span>
</code></pre>
<p>除此之外，还提供了逻辑运算符：</p>
<pre><code class="lang-cpp">x&amp;y     <span class="hljs-comment">// 按位与（bitwise and）</span>
x|y     <span class="hljs-comment">// 按位或（bitwise or）</span>
xˆy     <span class="hljs-comment">// 按位异或（bitwise exclusive or）</span>
~x      <span class="hljs-comment">// 取补（bitwise complement）</span>
x&amp;&amp;y    <span class="hljs-comment">// 逻辑与（logical and）</span>
x||y    <span class="hljs-comment">// 逻辑或（logical or）</span>
!x      <span class="hljs-comment">// 逻辑非(否定)（logical not(negation)）</span>
</code></pre>
<p>按位的逻辑运算，其结果的类型与操作数一致，值是对每个对应的位进行运算的结果。
逻辑运算符<code>&amp;&amp;</code> 和 <code>||</code> 依据操作数的值仅返回 <code>true</code> 或 <code>false</code>。</p>
<p>在赋值和算术运算中，C++ 会为操作数在基本类型之间执行任何有意义的转换，
以便它们可以任意混合：</p>
<pre><code class="lang-cpp"><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">some_function</span><span class="hljs-params">()</span>    <span class="hljs-comment">// 函数不返回任何值</span>
</span>{
    <span class="hljs-type">double</span> d = <span class="hljs-number">2.2</span>;     <span class="hljs-comment">// 初始化浮点数</span>
    <span class="hljs-type">int</span> i = <span class="hljs-number">7</span>;          <span class="hljs-comment">// 初始化整数</span>
    d = d+i;            <span class="hljs-comment">// 把和赋值给d</span>
    i = d*i;            <span class="hljs-comment">// 把积赋值给i；注意：double类型的 d*i 被截断为一个 int</span>
}
</code></pre>
<p>表达式里用到的转换被称为<em>常规算术转换（the usual arithmetic conversions）</em>，
旨在确保按操作数中最高的精度执行表达式运算。
比如说，<code>double</code> 和 <code>int</code> 的加法运算，以双精度浮点数算术执行。</p>
<p>请留意，<code>=</code> 是 赋值运算符，而 <code>==</code> 是进行相等性判定。</p>
<p>除了传统的算术和逻辑运算符，C++ 还提供了专门的运算符用于修改变量：</p>
<pre><code class="lang-cpp">x+=y    <span class="hljs-comment">// x = x+y</span>
++x     <span class="hljs-comment">// 自增： x = x+1</span>
x-=y    <span class="hljs-comment">// x = x-y</span>
--x     <span class="hljs-comment">// 自减： x = x-1</span>
x*=y    <span class="hljs-comment">// 倍增 x = x*y</span>
x/=y    <span class="hljs-comment">// 倍缩 x = x/y</span>
x%=y    <span class="hljs-comment">// x = x%y</span>
</code></pre>
<p>这些运算符简明、便利，用得很频繁。</p>
<p>表达式的估值顺序是从左至右，赋值除外，它是从右到左。
很不幸，函数参数的估值顺序是未指定。</p>
<p><a class="en-page-number" id="8"></a></p>
<h3 id="1.4.2">1.4.2 初始化 </h3>
<p>在某个对象被使用之前，必须给定一个值。
C++ 有多种初始化方法，比如上面用到的 <code>=</code>，
还有一种通用形式，基于花括号内被隔开的初值列表：</p>
<pre><code class="lang-cpp"><span class="hljs-type">double</span> d1 = <span class="hljs-number">2.3</span>;                <span class="hljs-comment">// d1 初始化为 2.3</span>
<span class="hljs-type">double</span> d2 {<span class="hljs-number">2.3</span>};                <span class="hljs-comment">// d2 初始化为 2.3</span>
<span class="hljs-type">double</span> d3 = {<span class="hljs-number">2.3</span>};              <span class="hljs-comment">// d3 初始化为 2.3（使用 { ... } 时，此处的 = 可有可无）</span>
complex&lt;<span class="hljs-type">double</span>&gt; z = <span class="hljs-number">1</span>;          <span class="hljs-comment">// 一个复数，使用双精度浮点数作为标量</span>
complex&lt;<span class="hljs-type">double</span>&gt; z2 {d1,d2};
complex&lt;<span class="hljs-type">double</span>&gt; z3 = {d1,d2};   <span class="hljs-comment">// （使用 { ... } 时，此处的 = 可有可无）</span>

vector&lt;<span class="hljs-type">int</span>&gt; v {<span class="hljs-number">1</span>,<span class="hljs-number">2</span>,<span class="hljs-number">3</span>,<span class="hljs-number">4</span>,<span class="hljs-number">5</span>,<span class="hljs-number">6</span>};    <span class="hljs-comment">// 一个承载 int 的 vector</span>
</code></pre>
<p><code>=</code> 是传统形式，可追溯至C语言，但如果你拿不准，请使用 <code>{}</code>-列表 这种通用形式。
最起码，在涉及信息损失的类型转换时，它不会袖手旁观。</p>
<pre><code class="lang-cpp"><span class="hljs-type">int</span> i1 = <span class="hljs-number">7.8</span>; <span class="hljs-comment">// i1 的值将是 7 （惊不惊喜，意不意外？）</span>
<span class="hljs-type">int</span> i2 {<span class="hljs-number">7.8</span>}; <span class="hljs-comment">// 错误：浮点数向整数转换</span>
</code></pre>
<p>很不幸，<em>缩窄转换（narrowing conversion）</em> 这种有损信息的形式，
比如<code>double</code>到<code>int</code>以及<code>int</code>到<code>char</code>，在使用<code>=</code>（而非<code>{}</code>）的时候，
会被默许并悄无声息地进行。
这种由隐式缩窄转换导致的问题，是对C语言向后兼容(§16.3)的代价。</p>
<p>常量(§1.6)必须初始化，变量也只该在极罕见的情况下不初始化。
在准备好合适的值以前，别引入这个名称。
对于用户定义的类型（比如<code>string</code>、<code>vector</code>、<code>Matrix</code>、
<code>Motor_controller</code>以及<code>Orc_warrior</code>）可将其定义为隐式初始化(§4.2.1)。</p>
<p>定义变量时，如果可以从初始值中推导出类型，就无需明确指定：</p>
<pre><code class="lang-cpp"><span class="hljs-keyword">auto</span> b = <span class="hljs-literal">true</span>;      <span class="hljs-comment">// bool类型</span>
<span class="hljs-keyword">auto</span> ch = <span class="hljs-string">&apos;x&apos;</span>;      <span class="hljs-comment">// char类型</span>
<span class="hljs-keyword">auto</span> i = <span class="hljs-number">123</span>;       <span class="hljs-comment">// int类型</span>
<span class="hljs-keyword">auto</span> d = <span class="hljs-number">1.2</span>;       <span class="hljs-comment">// double类型</span>
<span class="hljs-keyword">auto</span> z = <span class="hljs-built_in">sqrt</span>(y);   <span class="hljs-comment">// 无论sqrt(y)返回什么类型，z都被指定为该类型</span>
<span class="hljs-keyword">auto</span> bb {<span class="hljs-literal">true</span>};     <span class="hljs-comment">// bb是bool类型</span>
</code></pre>
<p>使用<code>auto</code>的情况下，我们往往用<code>=</code>，因为不涉及类型转化的隐患，
如果你更青睐<code>{}</code>初始化，但用无妨。</p>
<p>没有特定原因去指明类型时，就可以用<code>auto</code>，“特定原因”包括：</p>
<ul>
<li>如果该定义处在较大的作用域中，希望其类型对阅读源码读的人一目了然。</li>
<li>希望明确规定变量的取值范围或精度（比方说，想用<code>double</code>，而非<code>float</code>）。</li>
</ul>
<p>运用<code>auto</code>，可以避免冗余，也不用敲很长的类型名。
在泛型编程中这尤为重要，这种情况下，对象的确切类型难于知晓，
而且类型名可能还特别长(§12.2)。</p>
<p><a class="en-page-number" id="9"></a></p>
<h2 id="1.5">1.5 作用域和生命期 </h2>
<p>声明会把其名称引入到某个作用域：</p>
<ul>
<li><em>局部作用域（local scope）</em>：
  声明在函数(§1.3)或lambda表达式(§6.3.2)内部的名称，
  被称为<em>局部名称（local name）</em>。
  它的作用域从声明的位置，延续到其声明所驻的代码块末尾。
  <em>代码块（block）</em>由一对<code>{}</code>界定。函数参数的名称也被视为局部名称。</li>
<li><em>类作用域（class scope）</em>：
  定义在类(§2.2、§2.3、第4章)中，且在任何函数(§1.3)、
  lambda表达式(§6.3.2)和<code>enum类</code>(§2.5)之外的名称，
  被称为<em>成员名称（member name）</em>——也叫<em>类成员名称（class member name）</em>。
  其作用域从容纳它的类声明的左花括号<code>{</code>开始，到这个类声明的末尾。</li>
<li><em>命名空间作用域（namespace scope）</em>：
  如果名称被定义在一个命名空间（namespace）(§3.4)里，且在任何函数(§1.3)、
  lambda表达式(§6.3.2)、类(§2.2、§2.3、第4章)、和<code>enum类</code>(§2.5)之外，
  就称之为<em>命名空间成员名称（namespace member name）</em>。
  其作用域从声明所在位置开始，直至命名空间结尾。</li>
</ul>
<p>未定义于任何其它结构内的名称，被称作<em>全局名称（global name）</em>，
位于<em>全局命名空间（global namespace）</em>中。</p>
<p>此外，某些对象可以不具名，例如临时变量，以及通过<code>new</code>创建的对象。例如：</p>
<pre><code class="lang-cpp">vector&lt;<span class="hljs-type">int</span>&gt; vec;    <span class="hljs-comment">// vec是全局的（一个承载整数的全局 vector）</span>

<span class="hljs-keyword">struct</span> <span class="hljs-title class_">Record</span> {
    string name;    <span class="hljs-comment">// name 是Record的成员（string类型成员）</span>
    <span class="hljs-comment">// ...</span>
};

<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">fct</span><span class="hljs-params">(<span class="hljs-type">int</span> arg)</span>   <span class="hljs-comment">// fct是全局的（全局函数）</span>
                    <span class="hljs-comment">// arg是局部的（一个整数参数）</span>
</span>{
    string motto {<span class="hljs-string">&quot;Who dares wins&quot;</span>};    <span class="hljs-comment">// motto 是局部的</span>
    <span class="hljs-keyword">auto</span> p = <span class="hljs-keyword">new</span> Record{<span class="hljs-string">&quot;Hume&quot;</span>};        <span class="hljs-comment">// p指向一个不具名Record（通过 new 创建）</span>
    <span class="hljs-comment">// ...</span>
}
</code></pre>
<p>对象在使用前必须先被构造（初始化），并将在其作用域末尾被销毁。
对于命名空间中的对象，其销毁的时间点位于程序的终止。
对成员来说，其销毁的时间点，由持有它的对象的销毁时间点确定。
经由<code>new</code>创建的对象，将“存活”至被<code>delete</code>(§4.2.2)销毁为止。</p>
<h2 id="1.6">1.6 常量 </h2>
<p>关于不可变更，C++有两种概念：</p>
<ul>
<li><code>const</code>：相当于“我保证不会修改这个值”。
  它主要用于指定接口，对于通过指针以及引用传入函数的数据，无需担心其被修改。
  编译器为<code>const</code>作出的“保证”担保。一个<code>const</code>的值可在运行期间得出。</li>
</ul>
<p><a class="en-page-number" id="10"></a></p>
<ul>
<li><code>constexpr</code>：相当于“将在编译期估值”。
  它主要用于定义常量，指定该数据被置于只读内存（在这里被损坏的几率极低）中，
  并且在性能方面有益。
  <code>constexpr</code>的值必须由编译器算出。</li>
</ul>
<p>例如：</p>
<pre><code class="lang-cpp"><span class="hljs-keyword">constexpr</span> <span class="hljs-type">int</span> dmv = <span class="hljs-number">17</span>;             <span class="hljs-comment">// dmv是个具名常量</span>
<span class="hljs-type">int</span> var = <span class="hljs-number">17</span>;                       <span class="hljs-comment">// var不是常量</span>
<span class="hljs-type">const</span> <span class="hljs-type">double</span> sqv = <span class="hljs-built_in">sqrt</span>(var);       <span class="hljs-comment">// sqv是个具名常量，很可能要在运行时得出</span>

<span class="hljs-function"><span class="hljs-type">double</span> <span class="hljs-title">sum</span><span class="hljs-params">(<span class="hljs-type">const</span> vector&lt;<span class="hljs-type">double</span>&gt;&amp;)</span></span>;  <span class="hljs-comment">// sum不会修改其参数(§1.7)</span>

vector&lt;<span class="hljs-type">double</span>&gt; v {<span class="hljs-number">1.2</span>, <span class="hljs-number">3.4</span>, <span class="hljs-number">4.5</span>};   <span class="hljs-comment">// v不是一个常量</span>
<span class="hljs-type">const</span> <span class="hljs-type">double</span> s1 = <span class="hljs-built_in">sum</span>(v);           <span class="hljs-comment">// OK：sum(v)将在运行期估值</span>
<span class="hljs-keyword">constexpr</span> <span class="hljs-type">double</span> s2 = <span class="hljs-built_in">sum</span>(v);       <span class="hljs-comment">// 报错：sum(v)不是常量表达式</span>
</code></pre>
<p>如果函数要在<em>常量表达式（constant expression）</em>中使用，就是说，
用在由编译器估值的表达式里，则必须用<code>constexpr</code>定义。例如：</p>
<pre><code class="lang-cpp"><span class="hljs-function"><span class="hljs-keyword">constexpr</span> <span class="hljs-type">double</span> <span class="hljs-title">square</span><span class="hljs-params">(<span class="hljs-type">double</span> x)</span> </span>{ <span class="hljs-keyword">return</span> x*x; }

<span class="hljs-keyword">constexpr</span> <span class="hljs-type">double</span> max1 = <span class="hljs-number">1.4</span>*<span class="hljs-built_in">square</span>(<span class="hljs-number">17</span>);     <span class="hljs-comment">// OK 1.4*square(17) 是常量表达式</span>
<span class="hljs-keyword">constexpr</span> <span class="hljs-type">double</span> max2 = <span class="hljs-number">1.4</span>*<span class="hljs-built_in">square</span>(var);    <span class="hljs-comment">// 报错：var不是常量表达式</span>
<span class="hljs-type">const</span> <span class="hljs-type">double</span> max3 = <span class="hljs-number">1.4</span>*<span class="hljs-built_in">square</span>(var);        <span class="hljs-comment">// OK，可在运行时估值</span>
</code></pre>
<p><code>constexpr</code>函数可以用于非常量的参数，但此时其结果就不再是常量表达式。
对于<code>constexpr</code>函数，在无需常量表达式的语境里，就可以用非常量表达式参数调用它。
如此一来，就不必把本质上相同的函数定义两遍：一遍用于常量表达式，另一遍用于变量。</p>
<p>要成为<code>constexpr</code>，函数必须极其简单，且不能有副作用，且只能以传入的数据作为参数。
尤其是，它不能修改非局部变量，但里面可以有循环，以及它自己的局部变量。例如：</p>
<pre><code class="lang-cpp"><span class="hljs-function"><span class="hljs-keyword">constexpr</span> <span class="hljs-type">double</span> <span class="hljs-title">nth</span><span class="hljs-params">(<span class="hljs-type">double</span> x, <span class="hljs-type">int</span> n)</span>   <span class="hljs-comment">// 假定 n&gt;=0</span>
</span>{
    <span class="hljs-type">double</span> res = <span class="hljs-number">1</span>;
    <span class="hljs-type">int</span> i = <span class="hljs-number">0</span>;
    <span class="hljs-keyword">while</span> (i&lt;n) {   <span class="hljs-comment">// while-循环：在条件为真时执行(§1.7.1)</span>
        res*=x;
        ++i;
    }
    <span class="hljs-keyword">return</span> res;
}
</code></pre>
<p>在某些场合下，语言规则强制要求使用常量表达式（比如：数组界限(§1.7)、
case标签(§1.8)、模板的值参数(§6.2)，以及用<code>constexpr</code>定义的常量）。
其它情况下，编译期估值都侧重于性能方面。
抛开性能问题不谈，不变性（状态不可变更的对象）是一个重要的设计考量。</p>
<p><a class="en-page-number" id="11"></a></p>
<h2 id="1.7">1.7 指针、数组及引用 </h2>
<p>最基本的数据集合是：一串连续分配的，相同类型元素的序列，被称为<em>数组（array）</em>。
它基本脱胎于硬件。<code>char</code>类型元素的数组可以这样定义：</p>
<pre><code class="lang-cpp"><span class="hljs-type">char</span> v[<span class="hljs-number">6</span>];  <span class="hljs-comment">// 6个字符的数组</span>
</code></pre>
<p>与之相似，指针的定义是这样：</p>
<pre><code class="lang-cpp"><span class="hljs-type">char</span>* p;    <span class="hljs-comment">// 指向字符的指针</span>
</code></pre>
<p>在声明里，<code>[]</code>的意思是“什么什么的数组”，而<code>*</code>的意思是“指向什么什么东西”。
所有数组都以<code>0</code>作为下界，所以<code>v</code>有六个元素，从<code>v[0]</code>到<code>v[5]</code>。
数组容量必须是常量表达式(§1.6)。指针变量可持有相应类型对象的地址：</p>
<pre><code class="lang-cpp"><span class="hljs-type">char</span>* p = &amp;v[<span class="hljs-number">3</span>];    <span class="hljs-comment">// p指向v的第四个元素</span>
<span class="hljs-type">char</span> x = *p;        <span class="hljs-comment">// *p是p指向的对象</span>
</code></pre>
<p>在表达式里，一元前置运算符<code>*</code>的意思是“什么什么的内容”，
而一元前置运算符<code>&amp;</code>的意思是“什么什么的地址”。
我们可以把前面初始化定义的结果图示如下：</p>
<p><img src="img/ch01_03.png" alt="content-of-and-address-of"></p>
<p>思考一下，从一个数组里复制十个元素到另一个：</p>
<pre><code class="lang-cpp"><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">copy_fct</span><span class="hljs-params">()</span>
</span>{
    <span class="hljs-type">int</span> v1[<span class="hljs-number">10</span>] = {<span class="hljs-number">0</span>,<span class="hljs-number">1</span>,<span class="hljs-number">2</span>,<span class="hljs-number">3</span>,<span class="hljs-number">4</span>,<span class="hljs-number">5</span>,<span class="hljs-number">6</span>,<span class="hljs-number">7</span>,<span class="hljs-number">8</span>,<span class="hljs-number">9</span>};
    <span class="hljs-type">int</span> v2[<span class="hljs-number">10</span>];                 <span class="hljs-comment">// 将成为v1的副本</span>

    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">auto</span> i=<span class="hljs-number">0</span>; i!=<span class="hljs-number">10</span>; ++i)  <span class="hljs-comment">// 复制所有元素</span>
        v2[i]=v1[i];
    <span class="hljs-comment">// ...</span>
}
</code></pre>
<p><code>for</code>-语句可读作“把<code>i</code>置零；在<code>i</code>不等于<code>10</code>的时候，复制第<code>i</code>个元素并把<code>i</code>增1。”
自增运算符<code>++</code>应用在整数或浮点数变量上时，简单地给变量加<code>1</code>。
C++还提供一个简化的 <code>for</code>-语句，名为 区间-<code>for</code>-语句，是遍历序列最简单的方式：</p>
<p><a class="en-page-number" id="12"></a></p>
<pre><code class="lang-cpp"><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">print</span><span class="hljs-params">()</span>
</span>{
    <span class="hljs-type">int</span> v[] = {<span class="hljs-number">0</span>,<span class="hljs-number">1</span>,<span class="hljs-number">2</span>,<span class="hljs-number">3</span>,<span class="hljs-number">4</span>,<span class="hljs-number">5</span>,<span class="hljs-number">6</span>,<span class="hljs-number">7</span>,<span class="hljs-number">8</span>,<span class="hljs-number">9</span>};

    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">auto</span> x : v)        <span class="hljs-comment">// 针对v中的每个x</span>
        cout &lt;&lt; x &lt;&lt; <span class="hljs-string">&apos;\n&apos;</span>;

    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">auto</span> x : {<span class="hljs-number">10</span>,<span class="hljs-number">21</span>,<span class="hljs-number">32</span>,<span class="hljs-number">43</span>,<span class="hljs-number">54</span>,<span class="hljs-number">65</span>})
        cout &lt;&lt; x &lt;&lt; <span class="hljs-string">&apos;\n&apos;</span>;
    <span class="hljs-comment">// ...</span>
}
</code></pre>
<p>第一个 区间-<code>for</code>-语句 可读作“对于<code>v</code>的每个元素，从头至尾，复制进<code>x</code>并打印它。”
请留意，以列表初始化数组的时候，无需为它指定界限。
区间-<code>for</code>-语句 可用于任何的元素序列(§12.1)。</p>
<p>若不想把<code>v</code>中的值复制到变量<code>x</code>，而是仅让<code>x</code>引用一个元素，可以这么写：</p>
<pre><code class="lang-cpp"><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">increment</span><span class="hljs-params">()</span>
</span>{
    <span class="hljs-type">int</span> v[] = {<span class="hljs-number">0</span>,<span class="hljs-number">1</span>,<span class="hljs-number">2</span>,<span class="hljs-number">3</span>,<span class="hljs-number">4</span>,<span class="hljs-number">5</span>,<span class="hljs-number">6</span>,<span class="hljs-number">7</span>,<span class="hljs-number">8</span>,<span class="hljs-number">9</span>};

    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">auto</span>&amp; x : v)   <span class="hljs-comment">// 为v里的每个x加1</span>
        ++x;
    <span class="hljs-comment">// ...</span>
}
</code></pre>
<p>在声明中，一元前置运算符<code>&amp;</code>的意思是“引用到什么什么”。
引用和指针类似，只是在访问引用指向的值时，无需前缀<code>*</code>。
此外，在初始化之后，引用无法再指向另一个对象。</p>
<p>在定义函数参数时，引用就特别有价值。例如：</p>
<pre><code class="lang-cpp"><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">sort</span><span class="hljs-params">(vector&lt;<span class="hljs-type">double</span>&gt;&amp; v)</span></span>;   <span class="hljs-comment">// 把v排序（v是个承载double的vector）</span>
</code></pre>
<p>通过引用，我们确保了在调用<code>sort(my_vec)</code>的时候，不会复制<code>my_vec</code>，
并且被排序的确实是<code>my_vec</code>，而非其副本。</p>
<p>想要不修改参数，同时还避免复制的开销，可以用<code>const</code>引用(§1.6)。例如：</p>
<pre><code class="lang-cpp"><span class="hljs-function"><span class="hljs-type">double</span> <span class="hljs-title">sum</span><span class="hljs-params">(<span class="hljs-type">const</span> vector&lt;<span class="hljs-type">double</span>&gt;&amp;)</span>
</span></code></pre>
<p>接收<code>const</code>引用参数的函数很常见。</p>
<p>运算符（例如<code>&amp;</code>、<code>*</code>及<code>[]</code>）用在声明中的时候，
被称为<em>声明运算符（declarator operator）</em>：</p>
<pre><code class="lang-cpp">T a[n]  <span class="hljs-comment">// T[n]: 具有n个T的数组</span>
T* p    <span class="hljs-comment">// T*: p是指向T的指针</span>
T&amp; r    <span class="hljs-comment">// T&amp;: r是指向T的引用</span>
<span class="hljs-function">T <span class="hljs-title">f</span><span class="hljs-params">(A)</span>  <span class="hljs-comment">// T(A): f是个函数，接收一个A类型的参数，返回T类型的结果</span>
</span></code></pre>
<p><a class="en-page-number" id="13"></a></p>
<h3 id="1.7.1">1.7.1 空指针 </h3>
<p>我们尽量确保指针总是指向一个对象，以便解引用操作合法。
当没有对象可指，或我们想表达“不存在有效对象”（比如：列表的终结）的概念时，
就让指针的值为<code>nullptr</code>（空指针）。仅有一个<code>nullptr</code>，供所有指针类型共享：</p>
<pre><code class="lang-cpp"><span class="hljs-type">double</span>* pd = <span class="hljs-literal">nullptr</span>;
Link&lt;Record&gt;* lst = <span class="hljs-literal">nullptr</span>;    <span class="hljs-comment">// 指向承载Record的Link</span>
<span class="hljs-type">int</span> x = <span class="hljs-literal">nullptr</span>;                <span class="hljs-comment">// 报错：nullptr是指针而非整数</span>
</code></pre>
<p>检查指针参数，以确保其有所指，小心驶得万年船：</p>
<pre><code class="lang-cpp"><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">count_x</span><span class="hljs-params">(<span class="hljs-type">const</span> <span class="hljs-type">char</span>* p, <span class="hljs-type">char</span> x)</span>
    <span class="hljs-comment">// 统计p[]中出现x的次数</span>
    <span class="hljs-comment">// 假定p指向 以零结尾 的字符数组（或者不指向任何对象）</span>
</span>{
    <span class="hljs-keyword">if</span> (p==<span class="hljs-literal">nullptr</span>)
        <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
    <span class="hljs-type">int</span> count = <span class="hljs-number">0</span>;
    <span class="hljs-keyword">for</span> (; *p!=<span class="hljs-number">0</span>; ++p)
        <span class="hljs-keyword">if</span> (*p==x)
            ++count;
    <span class="hljs-keyword">return</span> count;
}
</code></pre>
<p>请留意，可以用<code>++</code>递增指针，使其指向数组的下一个元素；
以及，在用不到的时候，<code>for</code>-语句的初始化部分可以留空。</p>
<p>在<code>count_x()</code>的定义里，
假定了这个<code>char*</code>是一个 <em>C-风格 字符串（C-style string）</em>，
就是说，该指针指向一个以零结尾的<code>char</code>数组。
字符串文本中的字符是不可变的，为了能处理<code>count_x(&quot;Hello!&quot;)</code>，
我给<code>count_x()</code>声明了<code>const char*</code>参数。</p>
<p>在老式代码里，通常用<code>0</code>或<code>NULL</code>，而非<code>nullptr</code>。
但是，采用<code>nullptr</code>，
可以消除整数（比如<code>0</code>或<code>NULL</code>）和指针（比如<code>nullptr</code>）之间的混淆。</p>
<p>在<code>count_x()</code>的例子中，没使用<code>for</code>语句的初始化部分，
因此可以用更简单的<code>while</code>-语句：</p>
<pre><code class="lang-cpp"><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">count_x</span><span class="hljs-params">(<span class="hljs-type">const</span> <span class="hljs-type">char</span>* p, <span class="hljs-type">char</span> x)</span>
    <span class="hljs-comment">// 统计p[]中出现x的次数</span>
    <span class="hljs-comment">// 假定p指向 以零结尾 的字符数组（或者没有指向）</span>
</span>{
    <span class="hljs-keyword">if</span> (p==<span class="hljs-literal">nullptr</span>)
        <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
    <span class="hljs-type">int</span> count = <span class="hljs-number">0</span>;
    <span class="hljs-keyword">while</span> (*p) {
        <span class="hljs-keyword">if</span> (*p==x)
            ++count;
        ++p;
    }
    <span class="hljs-keyword">return</span> count;
}
</code></pre>
<p><a class="en-page-number" id="14"></a></p>
<p><code>while</code>-语句会一直执行到其条件变成<code>false</code>为止。</p>
<p>对数值的判定（比如<code>count_x()</code>里的<code>while(*p)</code>），
等同于将其与<code>0</code>比较（也就是<code>while(*p!=0)</code>）。
对指针指的判定（比如<code>if(p)</code>），
等同于将其与<code>nullptr</code>比较（也就是<code>if(p!=nullptr)</code>）。</p>
<p>不存在“空引用”。引用必须指向有效的对象（并且编译器的实现假定是这样）。
有些隐晦的小聪明可以绕过这些规则；别那么干。</p>
<h2 id="1.8">1.8 判定 </h2>
<p>C++有一套传统的语句表达选择和循环，
诸如<code>if</code>-语句、<code>switch</code>-语句、<code>while</code>-语句、<code>for</code>-语句。
举个例子，这有个很简单的函数，它向用户提问，并返回一个布尔值表示用户的反馈：</p>
<pre><code class="lang-cpp"><span class="hljs-function"><span class="hljs-type">bool</span> <span class="hljs-title">accept</span><span class="hljs-params">()</span>
</span>{
    cout &lt;&lt; <span class="hljs-string">&quot;Do you want to proceed (y or n)?\n&quot;</span>;   <span class="hljs-comment">// 输出问题</span>
    <span class="hljs-type">char</span> answer = <span class="hljs-number">0</span>;                                <span class="hljs-comment">// 初始化一个值，无需显示</span>
    cin &gt;&gt; answer;                                  <span class="hljs-comment">// 读取回应</span>
    <span class="hljs-keyword">if</span> (answer == <span class="hljs-string">&apos;y&apos;</span>)
        <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
    <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
}
</code></pre>
<p>跟输出运算符<code>&lt;&lt;</code>（“输至”）配对，运算符<code>&gt;&gt;</code>（“取自”）用于输入；
<code>cin</code>是标准输入流（第10章）。
<code>&gt;&gt;</code>右操作数的类型决定可接受的输入内容，这个右操作数也是输入操作的收货方。
待输出字符串末尾的字符<code>\n</code>表示另起一行(§1.2.1)。</p>
<p>请留意，<code>answer</code>定义在被需要的地方（而非更靠前的位置）。
声明能够出现在任何可以出现语句的地方。</p>
<p>可以改良此例，让它也接收一个<code>n</code>（代表“no”）作为回应：</p>
<pre><code class="lang-cpp"><span class="hljs-function"><span class="hljs-type">bool</span> <span class="hljs-title">accept2</span><span class="hljs-params">()</span>
</span>{
    cout &lt;&lt; <span class="hljs-string">&quot;Do you want to proceed (y or n)?\n&quot;</span>;   <span class="hljs-comment">// 输出问题</span>
    <span class="hljs-type">char</span> answer = <span class="hljs-number">0</span>;                                <span class="hljs-comment">// 初始化一个值，无需显示</span>
    cin &gt;&gt; answer;                                  <span class="hljs-comment">// 读取回应</span>

    <span class="hljs-keyword">switch</span> (answer) {
    <span class="hljs-keyword">case</span> <span class="hljs-string">&apos;y&apos;</span>:
        <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
    <span class="hljs-keyword">case</span> <span class="hljs-string">&apos;n&apos;</span>:
        <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
    <span class="hljs-keyword">default</span>:
        cout &lt;&lt; <span class="hljs-string">&quot;I&apos;ll take that for a no.\n&quot;</span>;
        <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
    }
}
</code></pre>
<p><a class="en-page-number" id="15"></a></p>
<p><code>switch</code>-语句把一个值跟一组常量进行比较。
这些常量被称为<code>case</code>-标签，必须互不相同，
如果该值与其中任何一个常量都不匹配，就执行<code>default</code>。
如果值不匹配任何<code>case</code>-标签，又没有<code>default</code>，就什么都不做。</p>
<p>如果一个函数里有<code>switch</code>-语句，在从该函数返回的时候，可以不退出<code>case</code>。
我们通常要继续执行<code>switch</code>-语句后续的内容。这可以使用<code>break</code>语句实现。
举个例子，这是个电子游戏的命令解析器，略原始，还有点小聪明：</p>
<pre><code class="lang-cpp"><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">action</span><span class="hljs-params">()</span>
</span>{
    <span class="hljs-keyword">while</span> (<span class="hljs-literal">true</span>) {
        cout &lt;&lt; <span class="hljs-string">&quot;enter action:\n&quot;</span>;  <span class="hljs-comment">// 询问动作</span>
        string act;
        cin &gt;&gt; act;                 <span class="hljs-comment">// 把字符串读入一个string</span>
        Point delta {<span class="hljs-number">0</span>,<span class="hljs-number">0</span>};          <span class="hljs-comment">// Point里存有一个{x,y}对</span>

        <span class="hljs-keyword">for</span> (<span class="hljs-type">char</span> ch : act) {
            <span class="hljs-keyword">switch</span> (ch) {
            <span class="hljs-keyword">case</span> <span class="hljs-string">&apos;u&apos;</span>:   <span class="hljs-comment">// 上（up）</span>
            <span class="hljs-keyword">case</span> <span class="hljs-string">&apos;n&apos;</span>:   <span class="hljs-comment">// 北（north）</span>
                ++delta.y;
                <span class="hljs-keyword">break</span>;
            <span class="hljs-keyword">case</span> <span class="hljs-string">&apos;r&apos;</span>:   <span class="hljs-comment">// 右（right）</span>
            <span class="hljs-keyword">case</span> <span class="hljs-string">&apos;e&apos;</span>:   <span class="hljs-comment">// 东（east）</span>
                ++delta.x;
                <span class="hljs-keyword">break</span>;
            <span class="hljs-comment">// ... more actions ...</span>
            <span class="hljs-keyword">default</span>:
                cout &lt;&lt; <span class="hljs-string">&quot;I freeze!\n&quot;</span>;
            }
            <span class="hljs-built_in">move</span>(current+delta*scale);
            <span class="hljs-built_in">update_display</span>();
        }
    }
}
</code></pre>
<p>与<code>for</code>-语句(§1.7)类似，<code>if</code>-语句接收一个值并对它判定。例如：</p>
<pre><code class="lang-cpp"><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">do_something</span><span class="hljs-params">(vector&lt;<span class="hljs-type">int</span>&gt;&amp; v)</span>
</span>{
    <span class="hljs-keyword">if</span> (<span class="hljs-keyword">auto</span> n = v.<span class="hljs-built_in">size</span>(); n!=<span class="hljs-number">0</span>) {
        <span class="hljs-comment">// ... 如果 n!=0 就走到这 ...</span>
    }
    <span class="hljs-comment">// ...</span>
}
</code></pre>
<p>此处的整数<code>n</code>的定义仅在<code>if</code>-语句内使用，以<code>v.size()</code>初始化，
并立即由分号后的条件<code>n!=0</code>进行判定。
在条件中声明的名称，其作用域同时囊括了<code>if</code>-语句的两个分支。</p>
<p><a class="en-page-number" id="16"></a></p>
<p>与<code>for</code>-语句的情况相同，把名称声明在<code>if</code>-语句的条件中，
目的是限制变量的作用域以提升可读性，并减少错误发生。</p>
<p>最常见的情况是针对<code>0</code>（或<code>nullptr</code>）判定变量。
这种情况下，无需明确提及判定条件。例如：</p>
<pre><code class="lang-cpp"><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">do_something</span><span class="hljs-params">(vector&lt;<span class="hljs-type">int</span>&gt;&amp; v)</span>
</span>{
    <span class="hljs-keyword">if</span> (<span class="hljs-keyword">auto</span> n = v.<span class="hljs-built_in">size</span>()) {
        <span class="hljs-comment">// ... 如果 n!=0 就走到这 ...</span>
    }
    <span class="hljs-comment">// ...</span>
}
</code></pre>
<p>请尽可能采用这种简洁的形式。</p>
<h2 id="1.9">1.9 映射至硬件 </h2>
<p>C++ 提供到硬件的直接映射。
当你用到基础运算，其操作由硬件执行，通常是单个的机器操作。
例如把两个<code>int</code>相加，<code>x+y</code>执行一条整数加法的机器指令。</p>
<p>C++编译器实现把机器的内存视为一连串的存储位置，
可向其中放置（带类型的）对象，并可用指针对其寻址：</p>
<p><img src="img/ch01_03.png" alt="content-of-and-address-of"></p>
<p>指针在内存里以机器地址表示，所以图中<code>p</code>的数值会是<code>3</code>。
如果这看起来像数组(§1.7)，那是因为在C++中，数组就是对“内存中一连串对象”的抽象。</p>
<p>这种基本语言构件向硬件的映射，对底层性能至关重要，数十年来，C和C++就是闻名于斯。
C和C++的基本机器模型基于计算机硬件，而非某种数学概念。</p>
<h3 id="1.9.1">1.9.1 赋值 </h3>
<p>内置类型的赋值就是简单的机器复制操作。例如：</p>
<pre><code class="lang-cpp"><span class="hljs-type">int</span> x = <span class="hljs-number">2</span>;
<span class="hljs-type">int</span> y = <span class="hljs-number">3</span>;
x = y; <span class="hljs-comment">// x 变成 3</span>
<span class="hljs-comment">// 注意： x==y</span>
</code></pre>
<p>显而易见。可以图示如下：</p>
<p><a class="en-page-number" id="17"></a></p>
<p><img src="img/ch01_04.png" alt="assignment-operation"></p>
<p>注意，两个对象是独立的。可以修改<code>y</code>的值却不牵连<code>x</code>。
比如<code>x=99</code>并不会修改<code>y</code>的值。
这一点对所有类型都成立，不仅仅是<code>int</code>，
这跟Java、C#以及其它语言不同，但和C语言一样。</p>
<p>如果想让不同的对象指向相同（共享）的值，必须明确指出。可以用指针：</p>
<pre><code class="lang-cpp"><span class="hljs-type">int</span> x = <span class="hljs-number">2</span>;
<span class="hljs-type">int</span> y = <span class="hljs-number">3</span>;
<span class="hljs-type">int</span>* p = &amp;x;
<span class="hljs-type">int</span>* q = &amp;y;    <span class="hljs-comment">// 现在 p!=q 且 *p!=*q</span>
p = q;          <span class="hljs-comment">// p 成了 &amp;y； 现在 p==q，因此（很明显）*p == *q</span>
</code></pre>
<p>可图示如下：</p>
<p><img src="img/ch01_05.png" alt="share-with-pointer"></p>
<p>用<code>88</code>和<code>92</code>作为<code>int</code>的地址，是随便选的。
与前例相同，可见 赋值目标 获得了 赋值源 的值，
结果是两个独立的对象（此处都是指针），具有相同的值。
就是说<code>p=q</code>导致<code>p==q</code>。执行<code>p=q</code>后，两个指针都指向<code>y</code>。</p>
<p>引用和指针都 指引向/指向 对象，而且在内存里都表现为机器地址。
但是在语言规则里，二者的使用形式不同。
向一个引用赋值，不会改变它引用的目标，而是会给它引用的对象赋值：</p>
<pre><code class="lang-cpp"><span class="hljs-type">int</span> x = <span class="hljs-number">2</span>;
<span class="hljs-type">int</span> y = <span class="hljs-number">3</span>;
<span class="hljs-type">int</span>&amp; r = x;     <span class="hljs-comment">// r 引用向 x</span>
<span class="hljs-type">int</span>&amp; r2 = y;    <span class="hljs-comment">// 现在r2引用向 y</span>
r = r2;         <span class="hljs-comment">// 经由r2读取,通过r写入：x变成3</span>
</code></pre>
<p>可图示如下：</p>
<p><img src="img/ch01_06.png" alt="how-references-work"></p>
<p>想要访问指针指向的值，需要借助<code>*</code>；但访问 引用所指的值 却是自动（隐式）的。</p>
<p>对于所有内置类型，以及设计良好
——提供<code>=</code>（赋值）和<code>==</code>（相等判定）——的用户定义类型（第2章），
执行过<code>x=y</code>后，都会得到<code>x==y</code>。</p>
<p><a class="en-page-number" id="18"></a></p>
<h3 id="1.9.2">1.9.2 初始化 </h3>
<p>初始化和赋值不一样。
一般来说，想要让赋值操作正确运行，被赋值对象必须已经有一个值。
另一边，初始化的任务是让一块未初始化过的内存成为一个有效的对象。
对绝大多数类型来说，针对 未初始化变量 的读取和写入都是未定义的（undefined）。
对于内置类型，这在引用身上尤其明显：</p>
<pre><code class="lang-cpp"><span class="hljs-type">int</span> x = <span class="hljs-number">7</span>;
<span class="hljs-type">int</span>&amp; r {x}; <span class="hljs-comment">// 把r绑定到x上（r引用向x）</span>
r = <span class="hljs-number">7</span>;      <span class="hljs-comment">// 不论r引用向什么，给它赋值</span>
<span class="hljs-type">int</span>&amp; r2;    <span class="hljs-comment">// 报错：未初始化引用</span>
r2 = <span class="hljs-number">99</span>;    <span class="hljs-comment">// 不论r2引用向什么，给它赋值</span>
</code></pre>
<p>很幸运，不存在未初始化的引用；
如果能，那么<code>r2=99</code>就会把<code>99</code>赋值给某个不确定的内存位置；
其结果会导致故障或者崩溃。</p>
<p><code>=</code>可用于初始化引用，但千万别被它搞糊涂了。例如：</p>
<pre><code class="lang-cpp"><span class="hljs-type">int</span>&amp; r = x; <span class="hljs-comment">// 把r绑定到x上（r引用向x）</span>
</code></pre>
<p>这依然是初始化r，并把它绑定到x上，而不涉及任何的值复制操作。</p>
<p>初始化和赋值的区别，对很多用户定义的类型
——比如<code>string</code>和<code>vector</code>——而言同样极度重要，
在这些类型中，被赋值的对象拥有一份资源，该资源最终将被释放(§5.3)。</p>
<p>参数传递和返回值返回的基本语义是初始化(§3.6)。
举例来说，传引用（pass-by-reference）就是这么实现的。</p>
<h2 id="1.10">1.10 忠告 </h2>
<p>此处的忠告是 C++ Core Guidelines [Stroustrup,2015] 的子集。
以类似 [CG: ES.23]的形式引用向核心指南，
其意思是 Expressions and Statement 章节的 第23条规则。
通常，核心指南提供更深入的理论和用例。</p>
<ul>
<li>[1] 别慌！船到桥头自然直；§1.1; [CG: In.0]。</li>
<li>[2] 不要专门或单独使用内置特性。
  恰恰相反，基本（内置）特性，最好借助程序库间接使用，
  比方说 ISO C++ 标准库（第8-15章）；[CG: P.10]。</li>
<li>[3] 想写出好程序，不必对C++掌握到巨细靡遗。</li>
<li>[4] 把力气用在编程技术上，别死磕语言特性。</li>
<li>[5] 有关语言定义相关问题的最终解释，
  请参考 ISO C++ 标准；§16.1.3; [CG: P.2]。</li>
<li>[6] 把有用的操作“打包”成函数，再取个好名字；§1.3; [CG: F.1]。</li>
<li>[7] 函数应当仅具有单一的逻辑功能；§1.3; [CG: F.2]。</li>
<li>[8] 保持函数简短；§1.3; [CG: F.3]。</li>
<li>[9] 当函数针对不同类型执行同样概念的操作时，请采用重载；§1.3。</li>
<li>[10] 当函数可能在编译期估值时，用<code>constexpr</code>声明它；§1.6; [CG: F.4]。</li>
</ul>
<p><a class="en-page-number" id="19"></a></p>
<ul>
<li>[11] 去理解基本语义向硬件的映射；§1.4, §1.7, §1.9, §2.3, §4.2.2, §4.4。</li>
<li>[12] 用数字分隔符为大文本值提高可读性；§1.4; [CG: NL.11]</li>
<li>[13] 不要使用复杂表达式；[CG: ES.40]</li>
<li>[14] 不要使用导致范围缩小的类型转换；§1.4.2; [CG: ES.46]</li>
<li>[15] 尽量让变量的作用域保持最小；§1.5</li>
<li>[16] 不要使用“魔数”；使用符号常量；§1.6; [CG: ES.45]。</li>
<li>[17] 尽量用不可变更的数据；§1.6; [CG: P.10]。</li>
<li>[18] 每个声明里有（且仅有）一个名称；[CG: ES.10]</li>
<li>[19] 保持常见和局部名称简短，让不常见和非局部名称长一些；[CG: ES.7]。</li>
<li>[20] 不要使用形似的名称；[CG: ES.8]。</li>
<li>[21] 不要使用全大写（<code>ALL_CAPS</code>）名称；[CG: ES.9]。</li>
<li>[22] 在提及类型的声明里，尽量用<code>{}</code>-初始化 语法；§1.4; [CG: ES.23]。</li>
<li>[23] 使用<code>auto</code>以避免重复输入类型名；§1.4.2; [CG: ES.11]。</li>
<li>[24] 尽量别弄出来未初始化的变量；§1.4; [CG: ES.20]。</li>
<li>[25] 尽量缩小作用域；§1.5; [CG: ES.5]。</li>
<li>[26] 如果在<code>if</code>-语句的条件中定义变量，尽量采用针对<code>0</code>的隐式判定；§1.8。</li>
<li>[27] 仅在涉及位操作时，使用<code>unsigned</code>；§1.4; [CG: ES.101] [CG: ES.106]。</li>
<li>[28] 确保对指针的使用简单且直白；§1.7; [CG: ES.42]。</li>
<li>[29] 用<code>nullptr</code>，而非<code>0</code>或<code>NULL</code>；§1.7; [CG: ES.47]。</li>
<li>[30] 在有值去初始化它之前，别声明变量；§1.7, §1.8; [CG: ES.21]。</li>
<li>[31] 别给直观的代码写注释； [CG: NL.1]。</li>
<li>[32] 用注释阐释意图；[CG: NL.2]。</li>
<li>[33] 保持缩进风格一致；[CG: NL.4]。</li>
</ul>
<blockquote id="fn_1">
<sup>1</sup>. 出自 外语教学与研究出版社 2015年10月 出版的《亨利六世 中：英汉对照》 由 覃学岚 译。 —— 译者注<a href="#reffn_1" title="Jump back to footnote [1] in the text."> ↩</a>
</blockquote>
<hr>

<script>console.log(window.location.pathname)</script>
<div id="disqus_thread"></div>
<script>

/**
*  RECOMMENDED CONFIGURATION VARIABLES: EDIT AND UNCOMMENT THE SECTION BELOW TO INSERT DYNAMIC VALUES FROM YOUR PLATFORM OR CMS.
*  LEARN WHY DEFINING THESE VARIABLES IS IMPORTANT: https://disqus.com/admin/universalcode/#configuration-variables*/
/*
var disqus_config = function () {
this.page.url = window.location.href;
this.page.identifier = window.location.pathname;
};
*/
(function() { // DON'T EDIT BELOW THIS LINE
var d = document, s = d.createElement('script');
s.src = 'https://a-tour-of-cpp-2nd-cn.disqus.com/embed.js';
s.setAttribute('data-timestamp', +new Date());
(d.head || d.body).appendChild(s);
})();
</script>
<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript" target="_blank">comments powered by Disqus.</a></noscript>
                                
    

                                </section>
                            
    </div>
    <div class="search-results">
        <div class="has-results">
            
            <h1 class="search-results-title"><span class='search-results-count'></span> results matching "<span class='search-query'></span>"</h1>
            <ul class="search-results-list"></ul>
            
        </div>
        <div class="no-results">
            
            <h1 class="search-results-title">No results matching "<span class='search-query'></span>"</h1>
            
        </div>
    </div>
</div>

                        </div>
                    </div>
                
            </div>

            
                
                <a href="./" class="navigation navigation-prev " aria-label="Previous page: 前言">
                    <i class="fa fa-angle-left"></i>
                </a>
                
                
                <a href="ch02.html" class="navigation navigation-next " aria-label="Next page: 2 用户定义类型">
                    <i class="fa fa-angle-right"></i>
                </a>
                
            
        
    </div>

    <script>
        var gitbook = gitbook || [];
        gitbook.push(function() {
            gitbook.page.hasChanged({"page":{"ch":1,"title":"1 基础知识","level":"1.3","depth":1,"next":{"title":"2 用户定义类型","level":"1.4","depth":1,"path":"ch02.md","ref":"ch02.md","articles":[]},"previous":{"title":"前言","level":"1.2","depth":1,"path":"README.md","ref":"README.md","articles":[]},"dir":"ltr"},"config":{"plugins":["@dogatana/page-toc-button","@dogatana/back-to-top-button","copy-code-button","forkmegithub","disqus-legacy"],"root":"./src","styles":{"website":"styles/website.css","pdf":"styles/pdf.css","epub":"styles/epub.css","mobi":"styles/mobi.css","ebook":"styles/ebook.css","print":"styles/print.css"},"pluginsConfig":{"@dogatana/back-to-top-button":{},"styles":{"website":"styles/website.css"},"search":{},"@dogatana/page-toc-button":{},"lunr":{"maxIndexSize":1000000,"ignoreSpecialCharacters":false},"fontsettings":{"theme":"white","family":"sans","size":2},"highlight":{},"disqus-legacy":{"shortname":"a-tour-of-cpp-2nd-cn"},"copy-code-button":{},"forkmegithub":{"color":"orange","url":"https://github.com/windsting/a-tour-of-cpp-2nd-cn"},"theme-default":{"styles":{"website":"styles/website.css","pdf":"styles/pdf.css","epub":"styles/epub.css","mobi":"styles/mobi.css","ebook":"styles/ebook.css","print":"styles/print.css"},"showLevel":false}},"theme":"default","author":"Windsting","pdf":{"pageNumbers":true,"fontSize":14,"fontFamily":"Arial","paperSize":"a5","chapterMark":"pagebreak","pageBreaksBefore":"/","margin":{"right":62,"left":62,"top":56,"bottom":56},"embedFonts":false},"structure":{"langs":"LANGS.md","readme":"README.md","glossary":"GLOSSARY.md","summary":"SUMMARY.md"},"variables":{},"title":"C++导览 第二版 简体中文版","language":"zh-hans","links":{"sidebar":{"Github Link":"https://github.com/windsting/a-tour-of-cpp-2nd-cn"}},"gitbook":"*","description":"A Tour of C++ (第二版) 非官方中译本"},"file":{"path":"ch01.md","mtime":"2023-02-16T11:51:51.529Z","type":"markdown"},"gitbook":{"version":"5.1.1","time":"2023-10-27T09:54:29.738Z"},"basePath":".","book":{"language":""}});
        });
    </script>
</div>

        
    <noscript>
        <style>
            .honkit-cloak {
                display: block !important;
            }
        </style>
    </noscript>
    <script>
        // Restore sidebar state as critical path for prevent layout shift
        function __init__getSidebarState(defaultValue){
            var baseKey = "";
            var key = baseKey + ":sidebar";
            try {
                var value = localStorage[key];
                if (value === undefined) {
                    return defaultValue;
                }
                var parsed = JSON.parse(value);
                return parsed == null ? defaultValue : parsed;
            } catch (e) {
                return defaultValue;
            }
        }
        function __init__restoreLastSidebarState() {
            var isMobile = window.matchMedia("(max-width: 600px)").matches;
            if (isMobile) {
                // Init last state if not mobile
                return;
            }
            var sidebarState = __init__getSidebarState(true);
            var book = document.querySelector(".book");
            // Show sidebar if it enabled
            if (sidebarState && book) {
                book.classList.add("without-animation", "with-summary");
            }
        }

        try {
            __init__restoreLastSidebarState();
        } finally {
            var book = document.querySelector(".book");
            book.classList.remove("honkit-cloak");
        }
    </script>
    <script src="gitbook/gitbook.js"></script>
    <script src="gitbook/theme.js"></script>
    
        
        <script src="gitbook/@dogatana/honkit-plugin-page-toc-button/plugin.js"></script>
        
    
        
        <script src="gitbook/@dogatana/honkit-plugin-back-to-top-button/plugin.js"></script>
        
    
        
        <script src="gitbook/gitbook-plugin-copy-code-button/toggle.js"></script>
        
    
        
        <script src="gitbook/gitbook-plugin-forkmegithub/plugin.js"></script>
        
    
        
        <script src="gitbook/gitbook-plugin-search/search-engine.js"></script>
        
    
        
        <script src="gitbook/gitbook-plugin-search/search.js"></script>
        
    
        
        <script src="gitbook/gitbook-plugin-lunr/lunr.min.js"></script>
        
    
        
        <script src="gitbook/gitbook-plugin-lunr/search-lunr.js"></script>
        
    
        
        <script src="gitbook/gitbook-plugin-fontsettings/fontsettings.js"></script>
        
    

    </body>
</html>

